package com.apes.fn.scm.retailOrder.service;

import com.apes.fn.business.fixedLoss.modle.LossQuotation;
import com.apes.fn.business.fixedLoss.repository.LossQuotationRepository;
import com.apes.fn.scm.retailOrder.model.RetailOrder;
import com.apes.fn.scm.retailOrder.model.RetailOrderItem;
import com.apes.fn.scm.retailOrder.repository.RetailOrderRepository;
import com.apes.fn.scm.retailOrder.service.account.RetailAccountData;
import com.apes.fn.scm.retailOrder.service.account.RetailAccountService;
import com.apes.fn.server.servicePlan.model.ServicePlanItem;
import com.apes.fn.server.servicePlan.repository.ServicePlanItemRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.Arith;
import com.apes.framework.util.LogicalUtil;
import com.apes.framework.util.MapUtil;
import com.apes.scm.account.account.model.AccountingMethod;
import com.apes.scm.account.account.model.InventoryBatch;
import com.apes.scm.account.account.model.InventoryMode;
import com.apes.scm.account.account.service.InventoryService;
import com.apes.scm.account.tax.model.Tax;
import com.apes.scm.account.tax.service.TaxService;
import com.apes.scm.contract.model.Contract;
import com.apes.scm.contract.service.ContractService;
import com.apes.scm.masterdata.frame.model.Store;
import com.apes.scm.masterdata.frame.repository.StoreRepository;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.model.VoucherInventory;
import com.apes.scm.voucher.model.VoucherItem;
import com.apes.scm.voucher.repository.VoucherInventoryRepository;
import com.apes.scm.voucher.service.BusinessType;
import com.apes.scm.voucher.service.VoucherType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

@Service("noInventoryRetailItemsService")
public class NoInventoryRetailItemsService extends DomainService {

    @Autowired
    private VoucherInventoryRepository voucherInventoryRepository;
    @Autowired
    private ContractService contractService;
    @Autowired
    private PartyRoleRepository partyRoleRepository;
    @Autowired
    private TaxService taxService;
    @Autowired
    private OrderPaintProductService orderPaintProductService;
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private RetailAccountService retailAccountService;

    public RetailOrder testProcess(SimpleRequest simpleRequest) {
        String id = simpleRequest.get("id");
        RetailOrder retailOrder = SpringManager.getBean(RetailOrderRepository.class).findOne(id);
        newProcess(retailOrder);
        return retailOrder;
    }

    /**
     * 生成采购凭证、生成销售凭证
     *
     * @param simpleRequest RetailOrder
     * @return RetailOrder
     */
    public RetailOrder process(SimpleRequest simpleRequest) {
        RetailOrder retailOrder = simpleRequest.getO(RetailOrder.class);
        if (!retailOrder.getState().equals("confirmed") && !retailOrder.getState().equals("done")) {
            throw new RuntimeException("场景流：标准零售，零售订单状态不对！");
        }

        newProcess(retailOrder);
        return retailOrder;
    }

    public void newProcess(RetailOrder retailOrder) {
        // 代销带安, 年审单独处理
        if ("annualAudit".equals(retailOrder.getOrderType())) {
            retailAccountService.process("annualAudit", new RetailAccountData(retailOrder));
        } else {
            retailAccountService.process("retailOutHelp", new RetailAccountData(retailOrder));
        }

        // 服务商品、油漆商品
        autRetailItemsProcess(retailOrder);

        // 销售凭证
        createWholeSaleVoucher(retailOrder);
    }


    /**
     * 仅处理采购凭证部分
     *
     * @param retailOrder RetailOrder
     */
    public void purchaseVoucher(RetailOrder retailOrder) {
        // 代销带安
        retailAccountService.process("retailOutHelp", new RetailAccountData(retailOrder));

        // 服务商品、油漆商品
        autRetailItemsProcess(retailOrder);
    }

    /**
     * 处理委托定损流程
     *
     * @param request RetailOrder
     * @return RetailOrder
     */
    public RetailOrder processWaterCar(SimpleRequest request) {
        RetailOrder retailOrder = request.getO(RetailOrder.class);
        if (!retailOrder.getState().equals("confirmed") && !retailOrder.getState().equals("done")) {
            throw new RuntimeException("场景流：委托定损销售，零售订单状态不对！");
        }

        newProcessWaterCar(retailOrder);
        return retailOrder;
    }

    private void newProcessWaterCar(RetailOrder retailOrder) {
        // 通用账目处理
        retailAccountService.process("retailOutHelp", new RetailAccountData(retailOrder));  // 代销带安
        autRetailItemsProcess(retailOrder);     // 服务商品、油漆商品

        // 判断是否为同公司委托定损
        if (Objects.equals(retailOrder.getDept().getCompany().getId(), retailOrder.getServiceDept().getCompany().getId())) {
            // 同公司委托定损
            retailAccountService.process("insuranceDiscount", new RetailAccountData(retailOrder));
        } else {

            // 销售凭证
            createBaseSaleVoucher(retailOrder);

            // 委托定损基地采购凭证/销售凭证
            retailAccountService.process("insuranceDiscountCross", new RetailAccountData(retailOrder));
        }
    }


    /**
     * 生成中的销售凭证
     *
     * @param saleOrder
     */
    private void createWholeSaleVoucher(RetailOrder saleOrder) {
        RetailOrder retailOrder = SpringManager.getBean(RetailOrderRepository.class).findOne(saleOrder.getId());

        Voucher voucher = getDefaultVoucher(retailOrder, BusinessType.SALE_ORDER);
        voucher.setInventoryMode(InventoryMode.IM_OWN);     //设置库存模式：自有
        voucher.setAccountingMethod(AccountingMethod.AM_PURCHASE);  // 核算方式：经销
        voucher.setCustomerExpand(retailOrder.getCustomerExpand().getId());

        voucher.setVoucherItems(
                retailOrder.getSaleItems().stream().map(
                        retailOrderItem -> {
                            VoucherItem voucherItem = getDefaultVoucherItem(retailOrderItem);
                            voucherItem.setOwner(retailOrder.getCompany());

                            // 检查是否为工单的内协的
                            if (retailOrderItem.getProductRule() == 20) {
                                ServicePlanItem servicePlanItem = SpringManager.getBean(ServicePlanItemRepository.class).findById(retailOrderItem.getOriginnumber()).orElse(null);
                                if (servicePlanItem != null) {
                                    voucherItem.setSupplier(servicePlanItem.getSupplier());
                                    voucherItem.setInventoryBatch(servicePlanItem.getInventoryBatch());
                                }
                            }
                            return voucherItem;
                        }).collect(Collectors.toSet())
        );
        voucher = createVoucher(voucher);
        sinopecInvoice(retailOrder, voucher);    // 中石化账单处理
    }

    private void sinopecInvoice(RetailOrder retailOrder, Voucher voucher){
        // 判断是否为中石化门店
        Store store = SpringManager.getBean(StoreRepository.class).findByDept(voucher.getDept());
        if (!store.isSinopec()) return;
        if (StringUtils.isEmpty(retailOrder.getSinopecNumber())) return;

        Map invoice = invoke("voucher.flow.invoice", MapUtil.mapped(voucher));

        // 查询中石化客户
        PartyRole sinopec = partyRoleRepository.findById("C0002496").get();
        invoice.put("partner", MapUtil.mapped(sinopec));

        if ("server".equals(retailOrder.getOrderType()) || LogicalUtil.in(retailOrder.getScene().getId(), "RO002", "RO003")) {
            // 服务来源的零售单 + 定损场景
            invoice.put("origin", retailOrder.getSource());
            invoice.put("originBusinessType", retailOrder.getSourceBusinessType());
        }
        invoke("invoice.create", MapUtil.mapped(invoice));
    }


    /**
     * 委托定损
     * 生成基地的销售凭证
     *
     * @param saleOrder
     */
    private void createBaseSaleVoucher(RetailOrder saleOrder) {
        RetailOrder retailOrder = SpringManager.getBean(RetailOrderRepository.class).findOne(saleOrder.getId());
        Voucher voucher = getDefaultVoucher(retailOrder, BusinessType.SALE_ORDER);
        voucher.setInventoryMode(InventoryMode.IM_OWN);     //设置库存模式：自有
        voucher.setAccountingMethod(AccountingMethod.AM_PURCHASE);  // 核算方式：经销
        voucher.setCustomerExpand(retailOrder.getCustomerExpand().getId());
        voucher.setPartner(retailOrder.getServiceDept().getCompany().getParty().getPatyRoleByType("Customer"));  // 基地公司

        Contract contract = contractService.getContract(retailOrder.getDept(), voucher.getPartner(), "distribution", "customer", "零售单销售业务");
        voucher.setContract(contract);

        // 修改凭证分类
        if ("RO003".equals(saleOrder.getScene().getId())) {
            voucher.setClassification(VoucherType.ENTRUST_LOSS);    // 委托定损
        }

        // 获取基地分红比例参数
        LossQuotation lossQuotation = SpringManager.getBean(LossQuotationRepository.class).findOne(retailOrder.getSource());
        double ratio = lossQuotation.getDividendStore(); // 从定损报价单上面取数

        voucher.setVoucherItems(
                retailOrder.getSaleItems().stream().map(
                        retailOrderItem -> {
                            VoucherItem voucherItem = getDefaultVoucherItem(retailOrderItem);
                            voucherItem.setOwner(retailOrder.getCompany());

                            // 计算比例对应的单价以及金额
                            voucherItem.setPriceUnit(Arith.round(retailOrderItem.getPriceUnit() * ratio, 4));

                            // 检查是否为工单的内协的
                            if (retailOrderItem.getProductRule() == 20) {
                                ServicePlanItem servicePlanItem = SpringManager.getBean(ServicePlanItemRepository.class).findById(retailOrderItem.getOriginnumber()).orElse(null);
                                if (servicePlanItem != null) {
                                    voucherItem.setSupplier(servicePlanItem.getSupplier());
                                    voucherItem.setInventoryBatch(servicePlanItem.getInventoryBatch());
                                }
                            }
                            return voucherItem;
                        }).collect(Collectors.toSet())
        );
        Voucher saleVoucher = createVoucher(voucher);

        //增加账单
        invoke("invoice.create", MapUtil.mapped(invoke("voucher.flow.invoice", MapUtil.mapped(saleVoucher))));
    }


    /**
     * 服务商品(非带安)
     *
     * @param retailOrder RetailOrder
     */
    private void autRetailItemsProcess(RetailOrder retailOrder) {
        // 服务商品
        Map<PartyRole, List<RetailOrderItem>> autRetailOrderItems = retailOrder.getSaleItems()
                .stream().filter((item) -> item.getProductRule() == 30)
                .collect(Collectors.groupingBy(RetailOrderItem::getOwner));
        if (autRetailOrderItems.isEmpty()) return;

        autRetailOrderItems.forEach(
                (company, orderItems) -> {
                    if (!retailOrder.getCompany().getId().equals(company.getId())) {
                        throw new RuntimeException("服务商品暂不支持跨公司交易");
                    }
                    orderItems.stream()
                            .map(item -> orderPaintProductService.setPaintInfo(retailOrder.getDept().getId(), item))
                            .collect(Collectors.groupingBy(RetailOrderItem::isPaintFlag))
                            .forEach((flag, item) -> {
                                if (flag) {
                                    //  油漆商品
                                    retailAccountService.process("retailPaint", new RetailAccountData(retailOrder, item));
                                } else {
                                    serviceProductVoucher(retailOrder, item, company);   //  服务商品
                                }
                            });
                });
    }

    private void serviceProductVoucher(RetailOrder retailOrder, List<RetailOrderItem> items, PartyRole company) {
        Voucher purVoucher = getDefaultVoucher(retailOrder, BusinessType.PURCHASE_ORDER);
        purVoucher.setCompany(company);
        purVoucher.setPartner(company.getParty().getPatyRoleByType("Supplier"));
        Contract contract = contractService.getContract(purVoucher.getDept(), purVoucher.getPartner(), "distribution", "supplier", "零售单服务商品自采业务");
        purVoucher.setContract(contract);
        purVoucher.setInventoryMode(purVoucher.getContract().getCooperation().getInventoryMode());     //设置库存模式：寄售
        purVoucher.setAccountingMethod(purVoucher.getContract().getCooperation().getAccountingMethod());  // 核算方式：采购价
        purVoucher.setClassification(VoucherType.SERVICE_PRODUCT);
        purVoucher.setCustomerExpand(retailOrder.getCustomerExpand().getId());

        PartyRole supplier = purVoucher.getPartner();
        purVoucher.setVoucherItems(
                items.stream().map(
                        item -> {
                            VoucherItem voucherItem = getDefaultVoucherItem(item);
                            voucherItem.setDiscount(0d);
                            Tax tax = taxService.getPurchaseTax(retailOrder.getCompany(), supplier, item.getProduct());//供应商进项税
                            voucherItem.setTax(tax);
                            voucherItem.setPriceUnit(0);
                            return voucherItem;
                        }
                ).collect(Collectors.toSet())
        );
        purVoucher = createVoucher(purVoucher);

        // 零售明细回写批次信息, 冻结批次数量
        retailItemsProcess(items, purVoucher);
    }

    private Voucher createVoucher(Voucher voucher) {
        return invoke("voucher.create", MapUtil.mapped(voucher));
    }

    private Voucher getDefaultVoucher(RetailOrder retailOrder, String businessType) {
        Voucher voucher = new Voucher();
        voucher.setDept(retailOrder.getDept());
        voucher.setCompany(retailOrder.getCompany());
        voucher.setPartner(retailOrder.getCompany().getParty().getPatyRoleByType("Customer"));
        voucher.setBusinessType(businessType);
        voucher.setClerk(retailOrder.getClerk()); //业务员
        voucher.setScene(retailOrder.getScene());
        voucher.setOrigin(retailOrder.getId());
        voucher.setOriginBusinessType(retailOrder.getInnerBusinessType());
        voucher.setSource(retailOrder.getId());
        voucher.setSourceBusinessType(retailOrder.getInnerBusinessType());
        return voucher;
    }

    private VoucherItem getDefaultVoucherItem(RetailOrderItem item) {
        VoucherItem voucherItem = new VoucherItem();
        voucherItem.setProduct(item.getProduct());
        voucherItem.setTax(item.getTax());
        voucherItem.setOwner(item.getOwner());
        voucherItem.setUom(item.getUom());          // 设置为销售的单位以及数量
        voucherItem.setProductQty(item.getProductUomQty());
        voucherItem.setPriceUnit(item.getPriceUnit());      // 默认为零售单价
        voucherItem.setInventoryBatch(item.getInventoryBatch());    // 指定销售批次
        voucherItem.setOriginItemId(item.getId());
        voucherItem.setSourceItemId(item.getId());
        voucherItem.setSupplier(item.getSupplier());
        voucherItem.setDiscount(item.getDiscountAmount());
        return voucherItem;
    }

    // 零售明细回写批次信息, 冻结批次数量
    private void retailItemsProcess(List<RetailOrderItem> retailOrderItems, Voucher voucher) {
        if (retailOrderItems.isEmpty()) return;

        String orderId = retailOrderItems.stream().findFirst().get().getOrder().getId();
        RetailOrder retailOrder = SpringManager.getBean(RetailOrderRepository.class).findOne(orderId);
        RetailOrder order = Optional.of(retailOrder).orElseThrow(() -> new RuntimeException(String.format("零售明细回写批次信息, 冻结批次数量时找不到主表[%s]", orderId)));

        Map<String, VoucherItem> voucherItemMap = voucher.getVoucherItems().stream().collect(Collectors.toMap(VoucherItem::getOriginItemId, x -> x));
        order.getSaleItems().stream().filter(retailOrderItems::contains).forEach(
                item -> {
                    if (!voucherItemMap.containsKey(item.getId())) throw new RuntimeException("找不到凭证明细对应！");
                    VoucherItem voucherItem = voucherItemMap.get(item.getId());
                    VoucherInventory voucherInventory = voucherInventoryRepository.findByVoucherItem(voucherItem)
                            .stream().findAny().orElseThrow(() -> new RuntimeException("找不到批次信息！"));
                    InventoryBatch inventoryBatch = voucherInventory.getInventoryBatch();

                    // 冻结批次数量
                    inventoryService.changeFrostQty(inventoryBatch, inventoryBatch.getUom(), inventoryBatch.getPurchaseQty(),
                            voucher.getCompany(), voucher.getInnerBusinessType(), voucher.getId(),
                            String.valueOf(voucherItem.getId()), "带安和服务商品零售处理 零售明细回写批次信息, 冻结批次数量");

                    item.setInventoryBatch(inventoryBatch);
                    item.setSupplier(voucherInventory.getInventorySupplier());
                    if (VoucherType.PAINT_PRODUCT.equals(voucher.getClassification())) {
                        item.setSupplier(voucherInventory.getInventorySupplier());
                        item.setPaintFlag(true);
                    }

                });
        SpringManager.getBean(RetailOrderRepository.class).save(order);
    }

}
